﻿using System;
using System.Net;
using AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox;
using AppLimit.CloudComputing.SharpBox;
using AppLimit.CloudComputing.SharpBox.Common;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using FbHelperWP7NonUi.BookStorage.DropBoxStorage.AsyncHelpClasses;
using System.IO;

namespace FbHelperWP7NonUi.BookStorage.DropBoxStorage
{
    internal sealed class AsyncStorageHelper
    {
        private enum State
        {
            BeforeWorking,
            Loginning,
            LoggedIn
        }

        private const string appKey = "5skc26l9lnz2lnk";
        private const string appSecret = "clpqj3qrgx8c13h";

        private readonly CloudStorage dropBoxStorage = new CloudStorage();

        private State state = State.BeforeWorking;

        public AsyncStorageHelper()
        {
        }

        #region Login

        public void BeginOpenStorage( string eMail, string password, AsyncRequestCompleted<LoginResult> callback )
        {
            if ( state != State.BeforeWorking )
                throw new Exception( "Wrong state of AsyncStorageHelper" );

            state = State.Loginning;

            BackgroundWorker loginWorker = new BackgroundWorker();

            loginWorker.DoWork += new DoWorkEventHandler( loginWorker_DoWork );
            loginWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler( loginWorker_RunWorkerCompleted );

            loginWorker.RunWorkerAsync( new LoginData( loginWorker, eMail, password, callback ) );
        }

        private void loginWorker_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e )
        {
            LoginResult result = ( LoginResult )e.Result;

            if ( result.Error != null )
                state = State.BeforeWorking;
            else
                state = State.LoggedIn;

            if ( result.Callback != null )
                result.Callback( result );
#if !WINDOWS_PHONE
            result.Worker.Dispose();
#endif
        }

        private void loginWorker_DoWork( object sender, DoWorkEventArgs e )
        {
            LoginData loginData = ( LoginData )e.Argument;

            try
            {
                var dropBoxConfig = CloudStorage.GetCloudConfigurationEasy( nSupportedCloudConfigurations.DropBox );

                var dropBoxCredentials = new DropBoxCredentials();

                dropBoxCredentials.ConsumerKey = appKey;
                dropBoxCredentials.ConsumerSecret = appSecret;
                dropBoxCredentials.UserName = loginData.EMail;
                dropBoxCredentials.Password = loginData.Password;

                dropBoxStorage.Open( dropBoxConfig, dropBoxCredentials );

                e.Result = new LoginResult( loginData );
            }
            catch ( Exception ex )
            {
                e.Result = new LoginResult( loginData, ex );
            }
        }
        #endregion

        #region GetDirectoryEntry

        public void BeginGetDirectoryEntry( string baseDirectory, AsyncRequestCompleted<GetDirectoryEntryResult> callback )
        {
            if ( state != State.LoggedIn )
                throw new Exception( "Wrong state of AsyncStorageHelper" );

            BackgroundWorker worker = new BackgroundWorker();

            worker.DoWork += new DoWorkEventHandler( GetDirectoryEntry_DoWork );
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler( GetDirectoryEntry_RunWorkerCompleted );

            worker.RunWorkerAsync( new GetDirectoryEntryData( worker, baseDirectory, callback ) );
        }

        private void GetDirectoryEntry_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e )
        {
            GetDirectoryEntryResult result = ( GetDirectoryEntryResult )e.Result;

            if ( result.Callback != null )
                result.Callback( result );
#if !WINDOWS_PHONE
            result.Worker.Dispose();
#endif
        }

        private void GetDirectoryEntry_DoWork( object sender, DoWorkEventArgs e )
        {
            GetDirectoryEntryData data = ( GetDirectoryEntryData )e.Argument;
            try
            {
                ICloudDirectoryEntry directoryEntry = dropBoxStorage.GetFolder( data.BaseDirectory );

                List<string> directories = new List<string>();
                List<string> files = new List<string>();

                foreach ( ICloudFileSystemEntry entry in directoryEntry )
                {
                    if ( entry is ICloudDirectoryEntry )
                        directories.Add( entry.Name );
                    else
                        files.Add( entry.Name );
                }

                e.Result = new GetDirectoryEntryResult( data, directories.AsReadOnly(), files.AsReadOnly() );
            }
            catch ( Exception ex )
            {
                e.Result = new GetDirectoryEntryResult( data, ex );
            }
        }
        #endregion

        #region Get File Entry

        public void BeginGetFileEntry( string path, AsyncRequestCompleted<GetFileEntryResult> callback )
        {
            BackgroundWorker worker = new BackgroundWorker();

            worker.DoWork += new DoWorkEventHandler( GetFileEntry_DoWork );
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler( GetFileEntry_RunWorkerCompleted );

            worker.RunWorkerAsync( new GetFileEntryData( worker, path, callback ) );
        }

        private void GetFileEntry_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e )
        {
            GetFileEntryResult result = ( GetFileEntryResult )e.Result;

            if ( result.Callback != null )
                result.Callback( result );
#if !WINDOWS_PHONE
            result.Worker.Dispose();
#endif
        }

        private void GetFileEntry_DoWork( object sender, DoWorkEventArgs e )
        {
            GetFileEntryData data = ( GetFileEntryData )e.Argument;
            try
            {
                string filePath = data.FilePath;

                string directoryPath = filePath.Substring( 0, filePath.LastIndexOf( '/' ) + 1 );
                string fileName = filePath.Substring( directoryPath.Length );

                ICloudDirectoryEntry directoryEntry = dropBoxStorage.GetFolder( directoryPath );

                ICloudFileSystemEntry file = dropBoxStorage.GetFile( fileName, directoryEntry );

                int lenght = ( int )file.Length;

                byte[] result = new byte[ lenght ];

                using ( Stream inputStream = file.GetDataTransferAccessor().GetDownloadStream() )
                {
                    inputStream.Read( result, 0, lenght );
                }

                e.Result = new GetFileEntryResult( data, result );
            }
            catch ( Exception ex )
            {
                e.Result = new GetFileEntryResult( data, ex );
            }
        }

        #endregion
    }
}
